package com.topc.code.judge.impl;

import cn.hutool.json.JSONUtil;
import com.topc.base.exception.Asserts;
import com.topc.code.judge.*;
import com.topc.code.judge.strategy.JudgeContext;
import com.topc.code.service.IProblemContentCommitService;
import com.topc.code.service.IProblemInfoService;
import com.topc.code.service.IProblemUserMidService;
import com.topc.problem.model.code.*;
import com.topc.problem.model.enums.JudgeInfoMessageEnum;
import com.topc.problem.model.enums.LanguageTypeEnum;
import com.topc.problem.model.enums.QuestionSubmitStatusEnum;
import com.topc.problem.model.po.*;
import com.topc.problem.model.vo.CompetitionCheckInfoVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Service
public class JudgeServiceImpl implements JudgeService {
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private IProblemContentCommitService problemContentCommitService;

    @Autowired
    private IProblemInfoService problemInfoService;

    @Autowired
    private IProblemUserMidService problemUserMidService;


    @Override
    public ProblemUserMid doJudge(long questionSubmitId, CompetitionCheckInfoVo competitionCheckInfoVo) {
        //传入题目的提交id，获取对应的题目，提交信息
        //寻找提交信息
        ProblemUserMid problemUserMid = problemUserMidService.getById(questionSubmitId);
        if (problemUserMid== null){
            Asserts.fail("提交信息不存在");
        }
        //寻找提交的对应题目信息
        Long problemId = problemUserMid.getProblemId();
        ProblemInfo problemInfo = problemInfoService.getById(problemId);
        if (problemInfo== null){
            Asserts.fail("题目不存在");
        }
//        //判断是否正在执行判题
//        if (!problemUserMid.getStatus().equals(QuestionSubmitStatusEnum.WAITING.getValue())){
//            Asserts.fail("题目正在判题中");
//        }
        //更新题目执行状态为RUNNING
        ProblemUserMid problemUserMidUpdate = new ProblemUserMid();
        problemUserMidUpdate.setId(questionSubmitId);
        problemUserMidUpdate.setStatus(QuestionSubmitStatusEnum.RUNNING.getValue());
        boolean update = problemUserMidService.updateById(problemUserMidUpdate);
        if (!update){
            Asserts.fail("更新题目执行状态失败");
        }
        //获取代码和对应语言
        Long contentId = problemUserMid.getContentId();
        ProblemContentCommit problemContentCommit = problemContentCommitService.getById(contentId);
        String codeContent = problemContentCommit.getContent();
        Integer codeTypeId = problemContentCommit.getCodeType();
        String language = LanguageTypeEnum.getEnumByText(codeTypeId).getValue();
        //调用沙箱，获取执行结果
        //调用判题模块
        CodeSandbox codeSandbox = CodeSandboxFactory.newInstance(language);
        //逻辑增强处理
        codeSandbox = new CodeSandboxProxy(codeSandbox);
        //获取输入用例
        System.out.println(problemId);
        ProblemSampleCollect problemSampleCollect = mongoTemplate.findById(problemId.toString(), ProblemSampleCollect.class);
        List<ProblemSample> problemSampleList = problemSampleCollect.getSamples();
        List<String> inputList = problemSampleList.stream().map(ProblemSample::getInput).collect(Collectors.toList());
        System.out.println("----正确输入样例："+inputList);
        //整合请求信息，代码，语言，测试样例
        ExecuteCodeRequest executeCodeRequest = ExecuteCodeRequest.builder()
                .code(codeContent)
                .language(language)
                .inputList(inputList)
                .build();
        //转为响应信息
        ExecuteCodeResponse executeCodeResponse = codeSandbox.executeCode(executeCodeRequest);
        System.out.println("----判题结果："+executeCodeResponse);
        List<String> outputList = executeCodeResponse.getOutputList();

        //根据沙箱的执行结果设置判题状态和信息
        JudgeContext judgeContext = new JudgeContext();
        judgeContext.setJudgeInfo(executeCodeResponse.getJudgeInfo());
        judgeContext.setInputList(inputList);
        judgeContext.setOutputList(outputList);
        judgeContext.setTimeList(executeCodeResponse.getTimeList());
        judgeContext.setMemoryList(executeCodeResponse.getMemoryList());
        judgeContext.setProblemSampleList(problemSampleList);
        judgeContext.setProblemInfo(problemInfo);
        judgeContext.setProblemUserMid(problemUserMid);
        judgeContext.setProblemContentCommit(problemContentCommit);
        JudgeInfo judgeInfo =executeCodeResponse.getJudgeInfo();
        if (!JudgeInfoMessageEnum.COMPILE_ERROR.getText().equals(judgeInfo.getMessage())){
            //执行结果校验策略
            System.out.println("执行校验策略");
            JudgeManager judgeManager = new JudgeManager();
            judgeContext = judgeManager.doJudge(judgeContext);
            judgeInfo=judgeContext.getJudgeInfo();
        }
        //判题结束，修改数据库中的判题结果
        problemUserMidUpdate  = new ProblemUserMid();
        problemUserMidUpdate.setId(questionSubmitId);
        problemUserMidUpdate.setStatus(QuestionSubmitStatusEnum.SUCCEED.getValue());
        problemUserMidUpdate.setConditionMid(JSONUtil.toJsonStr(judgeInfo));
        //非日常做题并且比赛结束，判题分数为0
        if (competitionCheckInfoVo.getCompetitionId()!=0&&competitionCheckInfoVo.getNowTime().isAfter(competitionCheckInfoVo.getEndTime())){
            problemUserMidUpdate.setScore(0);
        }else{
            problemUserMidUpdate.setScore(judgeContext.getScore());
        }
        update = problemUserMidService.updateById(problemUserMidUpdate);
        if (!update){
            Asserts.fail("更新题目执行状态失败");
        }
        //更新总分,找到用户竞赛报名记录(userNumber,competitionId)，当前用户提交记录，用户提交代码记录(competitionId,userNumber,problemId),判断差值
        //异步操作，执行更新总分流程
        if (competitionCheckInfoVo.getCompetitionId()!=0&&competitionCheckInfoVo.getNowTime().isBefore(competitionCheckInfoVo.getEndTime())){
            CompletableFuture.runAsync(() -> {
                problemUserMidService.updateCompetitionScore(problemUserMid);
            });
        }
        return problemUserMid;
    }

    @Override
    public JudgeContext doDebug(JudgeCompileInfo judgeCompileInfo) {
        String language = judgeCompileInfo.getLanguage();
        Long problemId = judgeCompileInfo.getProblemId();
        String codeContent = judgeCompileInfo.getCode();
        String input = judgeCompileInfo.getInput();
        //寻找提交的对应题目信息
        ProblemInfo problemInfo = problemInfoService.getById(problemId);
        if (problemInfo== null){
            Asserts.fail("题目不存在");
        }
        //调用判题模块
        CodeSandbox codeSandbox = CodeSandboxFactory.newInstance(language);
        //逻辑增强处理
        codeSandbox = new CodeSandboxProxy(codeSandbox);
        //获取输入用例
        List<String> inputList = new ArrayList<>();
        inputList.add(input);
        System.out.println("调试输入样例："+inputList);
        //整合请求信息，代码，语言，测试样例
        ExecuteCodeRequest executeCodeRequest = ExecuteCodeRequest.builder()
                .code(codeContent)
                .language(language)
                .inputList(inputList)
                .build();
        //转为响应信息
        ExecuteCodeResponse executeCodeResponse = codeSandbox.executeCode(executeCodeRequest);
        List<String> outputList = executeCodeResponse.getOutputList();
        //根据沙箱的执行结果设置判题状态和信息
        Integer codeType = LanguageTypeEnum.getEnumByValue(language).getText();
        ProblemContentCommit problemContentCommit = new ProblemContentCommit();
        problemContentCommit.setContent(codeContent);
        problemContentCommit.setCodeType(codeType);

        JudgeContext judgeContext = new JudgeContext();
        judgeContext.setJudgeInfo(executeCodeResponse.getJudgeInfo());
        judgeContext.setInputList(inputList);
        judgeContext.setOutputList(outputList);

        return judgeContext;
    }
}
